home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 2002 November / SGI Freeware 2002 November - Disc 3.iso / dist / fw_qt3.idb / usr / freeware / Qt / examples / thread / prodcons / prodcons.cpp.z / prodcons.cpp
Encoding:
C/C++ Source or Header  |  2002-04-08  |  6.7 KB  |  398 lines

  1. #include <qthread.h>
  2. #include <qwaitcondition.h>
  3. #include <qmutex.h>
  4. #include <qapplication.h>
  5. #include <qwidget.h>
  6. #include <qpushbutton.h>
  7. #include <qcheckbox.h>
  8. #include <qprogressbar.h>
  9. #include <qlayout.h>
  10. #include <qevent.h>
  11. #include <qlabel.h>
  12. #include <qcstring.h>
  13. #include <qtextstream.h>
  14. #include <qfile.h>
  15.  
  16. #include <stdio.h>
  17.  
  18. // 50kb buffer
  19. #define BUFSIZE (100*1000)
  20. #define PRGSTEP (BUFSIZE / 50)
  21. #define BLKSIZE (8)
  22. QByteArray bytearray;
  23.  
  24.  
  25. class ProdEvent : public QCustomEvent
  26. {
  27. public:
  28.     ProdEvent(long s, bool d)
  29.     : QCustomEvent(QEvent::User + 100), sz(s), dn(d)
  30.     { ; }
  31.  
  32.     long size() const { return sz; }
  33.     bool done() const { return dn; }
  34.  
  35.  
  36. private:
  37.     long sz;
  38.     bool dn;
  39. };
  40.  
  41.  
  42. class ProdThread : public QThread
  43. {
  44. public:
  45.     ProdThread(QObject *r, QMutex *m, QWaitCondition *c);
  46.  
  47.     void stop();
  48.     void run();
  49.  
  50.  
  51. private:
  52.     QObject *receiver;
  53.     QMutex *mutex;
  54.     QWaitCondition *condition;
  55.  
  56.     bool done;
  57. };
  58.  
  59.  
  60. ProdThread::ProdThread(QObject *r, QMutex *m, QWaitCondition *c)
  61.     : receiver(r), mutex(m), condition(c), done(FALSE)
  62. {
  63. }
  64.  
  65.  
  66. void ProdThread::stop()
  67. {
  68.     mutex->lock();
  69.     done = TRUE;
  70.     mutex->unlock();
  71. }
  72.  
  73.  
  74. void ProdThread::run()
  75. {
  76.     bool stop = FALSE;
  77.     done = FALSE;
  78.  
  79.     uchar *buffer = new uchar[BUFSIZE];
  80.     int pos = 0, oldpos = 0;
  81.     int loop = 1;
  82.     int lastpostedpos = 0;
  83.  
  84.     ProdEvent *pe = new ProdEvent(pos, done);
  85.     QThread::postEvent(receiver, pe);
  86.  
  87.     while (! stop) {
  88.     oldpos = pos;
  89.     int i;
  90.     for (i = 0; i < BLKSIZE && pos < BUFSIZE; i++) {
  91.         buffer[pos++] = (loop % 2) ? 'o' : 'e';
  92.     }
  93.  
  94.     mutex->lock();
  95.  
  96.     if (pos == BUFSIZE) {
  97.         done = TRUE;
  98.     }
  99.  
  100.     while (! bytearray.isNull() && ! stop) {
  101.             condition->wakeOne();
  102.             condition->wait(mutex);
  103.  
  104.         stop = done;
  105.     }
  106.  
  107.     stop = done;
  108.     bytearray.duplicate((const char *) (buffer + oldpos), pos - oldpos);
  109.     condition->wakeOne();
  110.  
  111.     mutex->unlock();
  112.  
  113.     if ( pos - lastpostedpos > PRGSTEP || stop ) {
  114.         lastpostedpos = pos;
  115.         ProdEvent *pe = new ProdEvent(pos, stop);
  116.         QThread::postEvent(receiver, pe);
  117.     }
  118.  
  119.     loop++;
  120.     }
  121.  
  122.     condition->wakeOne();
  123.  
  124.     delete [] buffer;
  125. }
  126.  
  127.  
  128. class ConsEvent : public QCustomEvent
  129. {
  130. public:
  131.     ConsEvent(long s)
  132.     : QCustomEvent(QEvent::User + 101), sz(s)
  133.     { ; }
  134.  
  135.     long size() const { return sz; }
  136.  
  137.  
  138. private:
  139.     long sz;
  140. };
  141.  
  142.  
  143. class ConsThread : public QThread
  144. {
  145. public:
  146.     ConsThread(QObject *r, QMutex *m, QWaitCondition *c);
  147.  
  148.     void stop();
  149.     void run();
  150.  
  151.  
  152. private:
  153.     QObject *receiver;
  154.     QMutex *mutex;
  155.     QWaitCondition *condition;
  156.  
  157.     bool done;
  158. };
  159.  
  160.  
  161. ConsThread::ConsThread(QObject *r, QMutex *m, QWaitCondition *c)
  162.     : receiver(r), mutex(m), condition(c), done(FALSE)
  163. {
  164. }
  165.  
  166.  
  167. void ConsThread::stop()
  168. {
  169.     mutex->lock();
  170.     done = TRUE;
  171.     mutex->unlock();
  172. }
  173.  
  174.  
  175. void ConsThread::run()
  176. {
  177.     bool stop = FALSE;
  178.     done = FALSE;
  179.  
  180.     QFile file("prodcons.out");
  181.     file.open(IO_WriteOnly);
  182.  
  183.     long size = 0;
  184.     long lastsize = 0;
  185.  
  186.     ConsEvent *ce = new ConsEvent(size);
  187.     QThread::postEvent(receiver, ce);
  188.  
  189.     while (! stop) {
  190.     mutex->lock();
  191.  
  192.     while (bytearray.isNull() && ! stop) {
  193.             condition->wakeOne();
  194.             condition->wait(mutex);
  195.  
  196.         stop = done;
  197.     }
  198.  
  199.     if (size < BUFSIZE) {
  200.         file.writeBlock(bytearray.data(), bytearray.size());
  201.         size += bytearray.size();
  202.         bytearray.resize(0);
  203.     }
  204.  
  205.     stop = done || size >= BUFSIZE;
  206.  
  207.     mutex->unlock();
  208.  
  209.     if ( size - lastsize > 1000 || stop ) {
  210.         lastsize = size;
  211.         ConsEvent *ce = new ConsEvent(size);
  212.         QThread::postEvent(receiver, ce);
  213.     }
  214.     }
  215.  
  216.     file.flush();
  217.     file.close();
  218. }
  219.  
  220.  
  221. class ProdCons : public QWidget
  222. {
  223.     Q_OBJECT
  224.  
  225. public:
  226.     ProdCons();
  227.     ~ProdCons();
  228.  
  229.     void customEvent(QCustomEvent *);
  230.  
  231.  
  232. public slots:
  233.     void go();
  234.     void stop();
  235.  
  236.  
  237. private:
  238.     QMutex mutex;
  239.     QWaitCondition condition;
  240.  
  241.     ProdThread *prod;
  242.     ConsThread *cons;
  243.  
  244.     QPushButton *startbutton, *stopbutton;
  245.     QCheckBox *loopcheckbox;
  246.     QProgressBar *prodbar, *consbar;
  247.     bool stopped;
  248. };
  249.  
  250.  
  251. ProdCons::ProdCons()
  252.     : QWidget(0, "producer consumer widget"), prod(0), cons(0), stopped(FALSE)
  253. {
  254.     startbutton = new QPushButton("&Start", this);
  255.     connect(startbutton, SIGNAL(clicked()), SLOT(go()));
  256.  
  257.     stopbutton = new QPushButton("S&top", this);
  258.     connect(stopbutton, SIGNAL(clicked()), SLOT(stop()));
  259.     stopbutton->setEnabled(FALSE);
  260.  
  261.     loopcheckbox = new QCheckBox("Loop", this);
  262.     loopcheckbox->setChecked(FALSE);
  263.  
  264.     prodbar = new QProgressBar(BUFSIZE, this);
  265.     consbar = new QProgressBar(BUFSIZE, this);
  266.  
  267.     QVBoxLayout *vbox = new QVBoxLayout(this, 8, 8);
  268.     vbox->addWidget(new QLabel(QString("Producer/Consumer using %1 byte buffer").
  269.                    arg(BUFSIZE), this));
  270.     vbox->addWidget(startbutton);
  271.     vbox->addWidget(stopbutton);
  272.     vbox->addWidget(loopcheckbox);
  273.     vbox->addWidget(new QLabel("Producer progress:", this));
  274.     vbox->addWidget(prodbar);
  275.     vbox->addWidget(new QLabel("Consumer progress:", this));
  276.     vbox->addWidget(consbar);
  277. }
  278.  
  279.  
  280. ProdCons::~ProdCons()
  281. {
  282.     stop();
  283.  
  284.     if (prod) {
  285.     delete prod;
  286.     prod = 0;
  287.     }
  288.  
  289.     if (cons) {
  290.     delete cons;
  291.     cons = 0;
  292.     }
  293. }
  294.  
  295.  
  296. void ProdCons::go()
  297. {
  298.     stopped = FALSE;
  299.  
  300.     mutex.lock();
  301.     startbutton->setEnabled(FALSE);
  302.     stopbutton->setEnabled(TRUE);
  303.  
  304.     // start the consumer first
  305.     if (! cons)
  306.         cons = new ConsThread(this, &mutex, &condition);
  307.     cons->start();
  308.  
  309.     // wait for consumer to signal that it has started
  310.     condition.wait(&mutex);
  311.  
  312.     if (! prod)
  313.         prod = new ProdThread(this, &mutex, &condition);
  314.     prod->start();
  315.     mutex.unlock();
  316. }
  317.  
  318.  
  319. void ProdCons::stop()
  320. {
  321.     if (prod && prod->running()) {
  322.     prod->stop();
  323.         condition.wakeAll();
  324.     prod->wait();
  325.     }
  326.  
  327.     if (cons && cons->running()) {
  328.     cons->stop();
  329.         condition.wakeAll();
  330.     cons->wait();
  331.     }
  332.  
  333.     startbutton->setEnabled(TRUE);
  334.     stopbutton->setEnabled(FALSE);
  335.  
  336.     stopped = TRUE;
  337. }
  338.  
  339.  
  340. void ProdCons::customEvent(QCustomEvent *e)
  341. {
  342.     switch (e->type()) {
  343.     case QEvent::User + 100:
  344.     {
  345.         // ProdEvent
  346.         ProdEvent *pe = (ProdEvent *) e;
  347.  
  348.         if (pe->size() == 0 ||
  349.         pe->size() == BUFSIZE ||
  350.         pe->size() - prodbar->progress() >= PRGSTEP)
  351.         prodbar->setProgress(pe->size());
  352.  
  353.         // reap the threads
  354.         if (pe->done()) {
  355.         bool loop = (loopcheckbox->isChecked() && ! stopped);
  356.  
  357.         stop();
  358.  
  359.         if (loop)
  360.             go();
  361.         }
  362.  
  363.         break;
  364.     }
  365.  
  366.     case QEvent::User + 101:
  367.     {
  368.         // ConsEvent
  369.         ConsEvent *ce = (ConsEvent *) e;
  370.  
  371.         if (ce->size() == 0 ||
  372.         ce->size() == BUFSIZE ||
  373.         ce->size() - consbar->progress() >= PRGSTEP)
  374.         consbar->setProgress(ce->size());
  375.  
  376.         break;
  377.     }
  378.  
  379.     default:
  380.     {
  381.         ;
  382.     }
  383.     }
  384. }
  385.  
  386.  
  387. int main(int argc, char **argv)
  388. {
  389.     QApplication app(argc, argv);
  390.     ProdCons prodcons;
  391.     app.setMainWidget(&prodcons);
  392.     prodcons.show();
  393.     return app.exec();
  394. }
  395.  
  396.  
  397. #include "prodcons.moc"
  398.